package com.ecommerce.auth.service.impl;

import com.ecommerce.auth.client.UserServiceClient;
import com.ecommerce.auth.dto.*;
import com.ecommerce.auth.entity.Role;
import com.ecommerce.auth.entity.User;
import com.ecommerce.auth.entity.UserRole;
import com.ecommerce.auth.repository.RoleRepository;
import com.ecommerce.auth.repository.UserRepository;
import com.ecommerce.auth.repository.UserRoleRepository;
import com.ecommerce.auth.service.AuthService;
import com.ecommerce.auth.util.JwtUtil;
import com.ecommerce.common.dto.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j

@Service
public class AuthServiceImpl implements AuthService {

    private final AuthenticationManager authenticationManager;
    private final UserRepository userRepository;
    private final RoleRepository roleRepository;
    private final UserRoleRepository userRoleRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtil jwtUtil;
    private final UserServiceClient userServiceClient;

    @Autowired
    public AuthServiceImpl(AuthenticationManager authenticationManager, UserRepository userRepository,
                         RoleRepository roleRepository, UserRoleRepository userRoleRepository,
                         PasswordEncoder passwordEncoder, JwtUtil jwtUtil, UserServiceClient userServiceClient) {
        this.authenticationManager = authenticationManager;
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
        this.userRoleRepository = userRoleRepository;
        this.passwordEncoder = passwordEncoder;
        this.jwtUtil = jwtUtil;
        this.userServiceClient = userServiceClient;
    }

    @Override
    public AuthResponse login(LoginRequest loginRequest) {
        try {
            // 验证用户名和密码
            User user = userRepository.findByUsername(loginRequest.getUsername())
                    .orElseThrow(() -> new RuntimeException("用户名或密码错误"));

            // 验证密码
            if (!passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
                throw new RuntimeException("用户名或密码错误");
            }

            // 检查用户是否被锁定
            if (user.getLocked()) {
                throw new RuntimeException("账户已被锁定，请联系管理员");
            }

            // 检查用户是否启用
            if (!user.getEnabled()) {
                throw new RuntimeException("账户已被禁用，请联系管理员");
            }

            // 更新最后登录时间
            user.setLastLoginTime(LocalDateTime.now());
            userRepository.save(user);

            // 获取用户角色
            List<String> roles = userRoleRepository.findRoleNamesByUserId(user.getId());

            // 生成令牌
            String token = jwtUtil.generateToken(user.getUsername(), user.getId(), roles, user.getUserType().name());
            String refreshToken = jwtUtil.generateRefreshToken(user.getUsername(), user.getId());

            return new AuthResponse(
                    token,
                    refreshToken,
                    user.getId(),
                    user.getUsername(),
                    user.getEmail(),
                    user.getPhoneNumber(),
                    user.getNickName(),
                    user.getAddress(),
                    user.getAvatarUrl(),
                    user.getGender().name(),
                    user.getLastLoginTime(),
                    roles,
                    user.getUserType().name()
            );
        } catch (Exception e) {
            throw new RuntimeException("登录失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public AuthResponse register(RegisterRequest registerRequest) {
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(registerRequest.getUsername())) {
            throw new RuntimeException("用户名已存在");
        }

        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(registerRequest.getEmail())) {
            throw new RuntimeException("邮箱已存在");
        }

        // 检查手机号是否已存在（仅当手机号不为空时检查）
        if (registerRequest.getPhoneNumber() != null && 
            !registerRequest.getPhoneNumber().trim().isEmpty() && 
            userRepository.existsByPhoneNumber(registerRequest.getPhoneNumber())) {
            throw new RuntimeException("手机号已存在");
        }

        // 创建新用户
        User user = new User();
        user.setUsername(registerRequest.getUsername());
        user.setPassword(passwordEncoder.encode(registerRequest.getPassword()));
        user.setEmail(registerRequest.getEmail());
        user.setPhoneNumber(registerRequest.getPhoneNumber());
        user.setNickName(registerRequest.getNickName() != null ? registerRequest.getNickName() : registerRequest.getUsername());
        user.setAddress(registerRequest.getAddress());
        user.setEnabled(true);
        user.setLocked(false);

        // 保存用户
        user = userRepository.save(user);

        // 分配默认角色
        Role defaultRole = roleRepository.findByName("ROLE_USER")
                .orElseGet(() -> {
                    Role role = new Role();
                    role.setName("ROLE_USER");
                    role.setDescription("普通用户角色");
                    role.setEnabled(true);
                    return roleRepository.save(role);
                });

        UserRole userRole = new UserRole();
        userRole.setUser(user);
        userRole.setRole(defaultRole);
        userRoleRepository.save(userRole);

        // 同步用户数据到用户服务
            try {
                log.info("开始同步用户数据到用户服务，用户ID: {}", user.getId());
                UserServiceClient.SyncUserRequest syncRequest = new UserServiceClient.SyncUserRequest(
                        user.getId(),
                        user.getUsername(),
                        user.getEmail(),
                        user.getPhoneNumber(),  // 使用认证服务的字段名
                        user.getNickName(),      // 使用认证服务的字段名
                        user.getAddress()
                );
                Result<String> syncResult = userServiceClient.syncUser(syncRequest);
                if (syncResult != null && syncResult.getCode() == 200) {
                    log.info("用户数据同步成功，用户ID: {}", user.getId());
                } else {
                    log.error("用户数据同步失败，用户ID: {}，返回结果: {}", user.getId(), syncResult);
                }
            } catch (Exception e) {
                log.error("同步用户数据到用户服务异常，用户ID: {}，错误: {}", user.getId(), e.getMessage(), e);
                // 同步失败不影响注册流程，只记录日志
            }

        // 获取用户角色
        List<String> roles = Collections.singletonList(defaultRole.getName());

        // 生成令牌
        String token = jwtUtil.generateToken(user.getUsername(), user.getId(), roles, user.getUserType().name());
        String refreshToken = jwtUtil.generateRefreshToken(user.getUsername(), user.getId());

        return new AuthResponse(
                token,
                refreshToken,
                user.getId(),
                user.getUsername(),
                user.getEmail(),
                user.getPhoneNumber(),
                user.getNickName(),
                user.getAddress(),
                user.getAvatarUrl(),
                user.getGender().name(),
                user.getLastLoginTime(),
                roles,
                user.getUserType().name()
        );
    }

    @Override
    public AuthResponse refreshToken(String refreshToken) {
        if (!jwtUtil.isRefreshToken(refreshToken)) {
            throw new RuntimeException("无效的刷新令牌");
        }

        if (jwtUtil.isInvalid(refreshToken)) {
            throw new RuntimeException("刷新令牌已过期");
        }

        String username = jwtUtil.getUsername(refreshToken);
        Long userId = jwtUtil.getUserId(refreshToken);

        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 获取用户角色
        List<String> roles = userRoleRepository.findRoleNamesByUserId(user.getId());

        // 生成新令牌
        String newToken = jwtUtil.generateToken(user.getUsername(), user.getId(), roles, user.getUserType().name());
        String newRefreshToken = jwtUtil.generateRefreshToken(user.getUsername(), user.getId());

        return new AuthResponse(
                newToken,
                newRefreshToken,
                user.getId(),
                user.getUsername(),
                user.getEmail(),
                user.getPhoneNumber(),
                user.getNickName(),
                user.getAddress(),
                user.getAvatarUrl(),
                user.getGender().name(),
                user.getLastLoginTime(),
                roles,
                user.getUserType().name()
        );
    }

    @Override
    public void logout(String token) {
        // 在实际应用中，可以将token加入黑名单
        // 这里暂时不做处理，因为JWT是无状态的
    }

    @Override
    @Transactional
    public void changePassword(Long userId, ChangePasswordRequest changePasswordRequest) {
        // 验证新密码和确认密码是否一致
        if (!changePasswordRequest.getNewPassword().equals(changePasswordRequest.getConfirmPassword())) {
            throw new RuntimeException("新密码和确认密码不一致");
        }

        // 查找用户
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 验证原密码
        if (!passwordEncoder.matches(changePasswordRequest.getOldPassword(), user.getPassword())) {
            throw new RuntimeException("原密码错误");
        }

        // 更新密码
        user.setPassword(passwordEncoder.encode(changePasswordRequest.getNewPassword()));
        userRepository.save(user);

        log.info("用户 {} 修改密码成功", userId);
    }

    @Override
    @Transactional
    public void updateProfile(Long userId, UpdateProfileRequest updateProfileRequest) {
        log.info("更新用户信息: {}", userId);

        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 检查邮箱是否被其他用户使用
        if (updateProfileRequest.getEmail() != null && !updateProfileRequest.getEmail().equals(user.getEmail())) {
            if (userRepository.existsByEmail(updateProfileRequest.getEmail())) {
                throw new RuntimeException("邮箱已被其他用户使用");
            }
            user.setEmail(updateProfileRequest.getEmail());
        }

        // 检查手机号是否被其他用户使用
        if (updateProfileRequest.getPhoneNumber() != null && !updateProfileRequest.getPhoneNumber().equals(user.getPhoneNumber())) {
            if (userRepository.existsByPhoneNumber(updateProfileRequest.getPhoneNumber())) {
                throw new RuntimeException("手机号已被其他用户使用");
            }
            user.setPhoneNumber(updateProfileRequest.getPhoneNumber());
        }

        // 更新其他字段
        if (updateProfileRequest.getNickName() != null) {
            user.setNickName(updateProfileRequest.getNickName());
        }
        if (updateProfileRequest.getAddress() != null) {
            user.setAddress(updateProfileRequest.getAddress());
        }
        if (updateProfileRequest.getAvatarUrl() != null) {
            user.setAvatarUrl(updateProfileRequest.getAvatarUrl());
        }

        user = userRepository.save(user);
        log.info("用户信息更新成功: {}", userId);
    }
}